using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEngine;

namespace AIOSAdapterSpace
{
    public class LoomForAIOS : MonoBehaviour
    {
        public struct DelayedQueueItem
        {
            public float time;

            public Action action;
        }

        public static int maxThreads = 8;

        private static int _numThreads;

        private List<Action> m_CurrentActions = new List<Action>();

        private List<Action> m_Actions = new List<Action>();

        private static bool m_InitDone;

        private static LoomForAIOS m_Current;

        private List<DelayedQueueItem> m_Delayed = new List<DelayedQueueItem>();

        private List<DelayedQueueItem> m_CurrentDelayed = new List<DelayedQueueItem>();

        public static LoomForAIOS Current
        {
            get
            {
                Initialize();
                return m_Current;
            }
        }

        public static void Initialize()
        {
            if (!m_InitDone && Application.isPlaying)
            {
                m_InitDone = true;
                GameObject obj = new GameObject("Loom");
                UnityEngine.Object.DontDestroyOnLoad(obj);
                m_Current = obj.AddComponent<LoomForAIOS>();
            }
        }

        public static void QueueOnMainThread(Action action)
        {
            if (action != null)
            {
                QueueOnMainThread(action, 0f);
            }
        }

        public static void QueueOnMainThread(Action action, float time)
        {
            if (time != 0f)
            {
                if (Current != null)
                {
                    lock (Current.m_Delayed)
                    {
                        Current.m_Delayed.Add(new DelayedQueueItem
                        {
                            time = Time.time + time,
                            action = action
                        });
                    }
                }
            }
            else if (Current != null)
            {
                lock (Current.m_Actions)
                {
                    Current.m_Actions.Add(action);
                }
            }
        }

        public static void RunAsync(Action a)
        {
            Initialize();
            while (_numThreads >= maxThreads)
            {
                Thread.Sleep(1);
            }

            Interlocked.Increment(ref _numThreads);
            ThreadPool.QueueUserWorkItem(RunAction, a);
        }

        private static void RunAction(object action)
        {
            try
            {
                ((Action)action)();
            }
            catch
            {
            }
            finally
            {
                Interlocked.Decrement(ref _numThreads);
            }
        }

        private void OnDisable()
        {
            if (m_Current == this)
            {
                m_Current = null;
            }
        }

        private void Update()
        {
            if (m_Actions.Count > 0)
            {
                lock (m_Actions)
                {
                    m_CurrentActions.AddRange(m_Actions);
                    m_Actions.Clear();
                }

                try
                {
                    foreach (Action currentAction in m_CurrentActions)
                    {
                        currentAction();
                    }
                }
                finally
                {
                    m_CurrentActions.Clear();
                }
            }

            if (m_Delayed.Count <= 0)
            {
                return;
            }

            lock (m_Delayed)
            {
                m_CurrentDelayed.AddRange(m_Delayed.Where((DelayedQueueItem d) => d.time <= Time.time));
                foreach (DelayedQueueItem item in m_CurrentDelayed)
                {
                    m_Delayed.Remove(item);
                }
            }

            try
            {
                foreach (DelayedQueueItem item2 in m_CurrentDelayed)
                {
                    item2.action();
                }
            }
            finally
            {
                m_CurrentDelayed.Clear();
            }
        }
    }
}
